<?
/**
Класс View - библиотека функций для отображения  элементов  веб-страницы (генераторы HTML кода).

	
	Базовые методы:
		View::menu			- генерирует меню навигации
		View::pagination	- генерирует постраничную навигацию
		View::template  	- выполняет указанный шаблон, подставляя в него данные
		View::field			- выполняет шаблон fields.php для отображения полей форм
		(???) View::register_dir 	- регистрирует директорию для поиска файла шаблона
		
	
	
	Класс View может дополняться и расширятся методами модулей.
	
	Класс View наследуется от базового класса View_Core и содержит динамически формируемый список функций - алиасов для зарегистрированых функций модулей. Функции модулей регистрируются с помощью метода Core::register_view($view_id, 'module::func')
	
	Например, в файле blocks.class.php перед объявления основного класса мы регистрируем функцию-вид (генератор HTML):
	
	Core::register_view('block','Blocks::view');
	
	class Blocks {
		...
		function view($block_id){
			...
		}
		
	}
	
	Теперь в шаблонах мы можем использовать метод View::block($block_id) - что выглядит логично и понятно	
	
	(TODO: как вариант можно регистрировать функции-виды не в файле класса (который теоретически может загрузиться позже модуля View), а в конфиге модуля (module_config.php), который уж точно будет загружен и обработан перед загрузкой класса View)
	
**/


 

// базовый класс, от которого ниже наследуется класс View
class View_Core { 

	
	
/* === View::menu ===  
	
	View::menu( $params=array() )  - выводит иерархическое меню навигации с использованием заданных шаблонов дизайна и параметров
	
	@return (void / HTML string) - по умолчанию ничего не возвращает, только выводит меню. В случае, если установлен $params['return'] , возвращает HTML код меню	

	
	@param (array)$params - ассоциативный массив с параметрами и шаблонами для построения меню, может содержать следущие элементы: 
      
	  === Массив $params : парамеры работы функции  ===
	  
		'return'	-	возвращать (или выводить) результат  функции View::menu . По умолчанию  'return'=false и функция выводит меню в макет и ничего не возвращает.
		
		'template'  - Ссылка на файл-шаблон с готовым набор параметров внешнего вида.   (Варианты: 'params_id' /  или может 'params_template' /  'params_set' / 'params_include' / 'params_import' / 'import_params'  - id набора предустановленных параметров из каталога готовых меню)
		
		=== Массив $params : Параметры выборки страниц  ===
	
		'is_admin'   - (default=0) если 1, то выводятся скрытые страницы
	
		'menu_id'    - (default='', выбираются все страницы) идентификатор меню, который должен быть установлен у выбираемых страниц  (идентификаторы меню описываются в файле design_config.php в папке дизайна, каждая страница может быть прикреплена к одном или нескольким меню)
	
		'parent_id'  - (default=0) id родительской страницы для страниц первого уровня в меню. Сама родительская страница не входит в меню. В качестве значения можно использовать 0 (корень сайта), число (id конкретной страницы) или макропеременные - '%current_id%' (id текущей страницы), '%parent_id%' (id родительской страницы).
		
		'max_depth'	- максимальная глубина меню, число от 1 и более. Если не указано - то глубина выборки не ограниченна

		'min_level'	- минимальный уровень страниц (начиная с 1)
		'max_level'	- макисмлаьный уровень страниц (начиная с 1)
	
	
		=== Массив $params :  Шаблоны дизайна для меню  ===
		
		(если ни один шаблон не указан, то используются дефотлтные шаблоны, 
		 описанные ниже, а если хоть один шаблон указан, то остальные по умолчанию = '')
	
        'prefix'	-  префикс перед списком элементов. 
        'suffix'	-  суффикс после списка элементов. 
        'link'		-  шаблон для обычного пункта меню.  
		   
        'active'    -  шаблон для активного пункта меню (т.е. совпадает с текущей страницей или родитель текущей страницы)  (если не указано, то используется шаблон  'link')
		
		'current'    -  шаблон для активного пункта меню, в точности совпадающего с текущей страницей  (если не указано, то используется шаблон  'active' или 'link')
		
		'parent'	- шаблон для родительского пункта меню (содержащего подстраницы в выборке) (если не указано, то используется шаблон  'link')
		
		'parent_active' - шаблон для родительского активного пункта меню (если не указано, то используется шаблон  'active' или  'parent' или 'link')
		
		'parent_current' - шаблон для родительского активного пункта меню, в точности совпадающего с текущей страницей, (если не указано, то используется шаблон  'parent_active'  или 'active' или  'parent' или 'link' )
           
        'divider' 	- разделитель между элементами меню
           
        'sub_templates' -  шаблоны для вложенных меню; если не указано, то используются  шаблоны, указазнные ранее. Этот массив может также содержать элемент 'sub_templates' (с шаблонами для меню 3го уровня), и т.д. Если элемент этого массива содержит макропеременную '%inherit%' - то вместо неё подставляется (наследуется) соответсвтующий шаблон предыдущего уровня.
                            
        
		===  Дефолтные значения параметров:  ===
		
		$default_params = array(
			'parent_id'	=> 0,	// все страницы от корня сайта
			'is_admin'	=> 0,	// только включенные страницы
			'menu_id'	=> '',	// независимо от меню
						
			// шаблоны дизайна для меню:
			
			'prefix'	=> '<ul class=depth%depth% >',
			'suffix'	=> '</ul>',
			'link'		=> '
				<li class="%active% %parent%" ><a href="%url%" >%title%</a> 
					%submenu%
				',
			'divider'	=> "\n",
			
			'sub_templates'	=> null, // наследуются
			
		);
        
===  %Макропеременные% для использования в  шаблонах дизайна меню:  ===
		
		// свойства и параметры процесса вычисления меню
		
		%depth%		-  заменяется на число - текущая глубина в меню (начинается с 1)
		%submenu%	-  заменяется на HTML код вложенного меню (если есть подстраницы) или пустую строку (если нет подстраниц).  
		%inherit%	-  заменяется на шаблон предыдущего уровня (используется в шаблонах секции subtemplates)
		%active%	-  содержит строку 'active' если данный пункт меню является активным (является текущей старнцией или содержит текущую страницу как подстраницу )
		%current%  -  содержит строку 'current' если данный пункт меню совпадает с текущей страницей
		%parent%	-  содержит строку 'parent' если данный пункт меню является родителем (т.е. имеет подстраницы в выборке) 
		%first%		- содержит строку 'first', если это первый пункт меню на одном уровне 
		%last%		- содержит строку 'last', если это последний пункт меню на одном уровне 
		%counter%	- число, номер пункта меню в текущей группе оного уровня
		
		// все свойства страницы для пункта меню:
		
		%title%	- название страницы для меню 
		%url%	- URL адрес страницы
		%img%	- картинка страницы
		%img_thumb% - миниатюра картинки страницы
		%show%	-	число 0 или 1 в зависимости от соовтетсвтующего свойства старницы
		... и все другие свойства старницы, какие ещё могут быть добавлены или установлены (напрмер, %tooltip% , %page_title% , %page_h1% , %parent_id% , %page_order% , %color% , и т.д. )
		
		// все свойства теекущей страницы:
		
		%current_title%	- название страницы для меню 
		%current_url%	- URL адрес страницы
		%current_img%	- картинка страницы
		%current_id%	- id текущей страницы
		
		// все свойства родительской страницы
		%parent_id% , %parent_title% , %parent_url%
		
		Нераспознанные макро-переменные заменяются на пустую строку (например %tooltip% замениться на пустую строку, если у страницы нет такого свойства).
    
    
	===  Примеры решений ===
	 
	# стандартное многоуровневое меню
		
		View::menu();
		
		Пример вывода:
		
		<ul class=depth1 >
			<li class="" ><a href="/" >Главная</a> 
			<li class="parent active" >
				<a class="parent active" href="/about/" >О компании</a> 
				
				<ul class=depth2 >
					<li class="active current" >
						<a  class="active current" href="/about/firma/" >О нас</a> 
					<li class="" ><a href="/about/history/" >История</a> 
				</ul>
				
			<li class="" ><a href="/services/" >Услуги</a> 
		</ul>
		
		
	 
	# корневое одноуровневое меню
		
		View::menu(array(
			'parent_id'	=> 0,		// все страницы от корня сайта
			'menu_id'	=> 'top',	// id меню
			'max_depth'	=> 2,		// максимальная глубина меню 
			
			'prefix'	=> '',
			'suffix'	=> '',
			'link'		=> '<a class="%active%" href="%url%" >%title%</a> ',
			'divider'	=> " | ",
		));
	 	 
	 
	# корневое двухуровневое меню
	 
	 View::menu(array(
			'parent_id'	=> 0,		// все страницы от корня сайта
			'menu_id'	=> 'top',	// id меню
			'max_depth'	=> 2,		// максимальная глубина меню 
			
			'prefix'	=> '<TABLE><TR>',
			'suffix'	=> '</TABLE>',
			'link'		=> '<TD> <a class="%active%" href="%url%" >%title%</a> %submenu%',
			'divider'	=> " | ",
			
			'sub_templates'	=> array(
				'prefix'	=> '<small>',
				'suffix'	=> '</small>',
				'link'		=> '<BR> <a class="%active%" href="%url%" >%title%</a>' ,
			),
		));
	 
	 
	# горизонтальное выпадающее меню, до 3х уровней вложенности
	
		(http://www.cssplay.co.uk/menus/dd_valid.html)
	 
	  View::menu(array(
			'parent_id'	=> 0,		// все страницы от корня сайта
			'menu_id'	=> 'top',	// id меню
			
			'prefix'	=> ' 
				<link href="'.$theme_folder.'/files/menu-hor-drop.css" 
					rel="stylesheet" type="text/css" />  
				<div class="menu-hor-drop">
				<ul>
				',
			
			'suffix'	=> '</ul></div>',
			
			'link'		=> '<li><a href="%url%" >%title%</a></li>',
			
			'parent'	=>  '
				<li ><a class="hide" href="%url%" title="%tooltip%" >%title% <b>&gt;</b></a>
				
					<!--[if lte IE 6]>
						<a class="sub" href="%url%" title="%tooltip%">%title% <b>&gt;</b>
						<table><tr><td>
					<![endif]-->
					
					%submenu%
					
					<!--[if lte IE 6]>
						</td></tr></table>
						</a>
					<![endif]-->
				
				</li>
				',
			
			'divider'	=> " \n ",
			
			'sub_templates'	=> array(
				'prefix'	=> '<ul>',
				'suffix'	=> '</ul>',
				'link'		=> '%inherit%', // наследуется шаблон предыдущего уровня
				'parent'	=> '%inherit%', // наследуется шаблон предыдущего уровня
			),
		));
	 
	 
	 
	 
	 
	# меню с фикированной корневой страницей, неограниченной глубины, под-страницы отображаются только у активных страниц   
		
		View::menu(array(
			'parent_id'	=> 25,		// id корневой страницы
			
			'prefix'	=> '<ul>',
			'suffix'	=> '</ul>',
			'link'		=> '<li><a href="%url%" >%title%</a>',
			'active'	=> '<li><a class="%active%" href="%url%" >%title%</a> %submenu%',
			
			'divider'	=> " \n ",
			
			),
		));
	 
	
	 
	# меню с динамическим корнем (текущая старница) и глубиной в один уровень, т.е. отображаются только непосредственые подстраницы текущей страницы 
	
	View::menu(array(
			'parent_id'	=> '%current_id%',	// корневая страница - текущая активная
			'max_depth'	=> 1,	// максимальная глубина меню
			
			// над меню подразделов отображаем заголовок текущей страницы 
			'prefix'	=> ' <b>%current_title%</b>
							 <ul>
							',
			'suffix'	=> '</ul>',
			'link'		=> '<li><a class="%active%" href="%url%" >%title%</a>',
			
			'divider'	=> " \n ",
			
			),
		));
	
	
	
	# меню 2го уровня, c динамическим корнем, и глубиной в 2 уровеня. Если у текущей страницы нет подстраниц 2го или 3го уровня, то меню пустое. 
	
		View::menu(array(
			'parent_id'	=> '%current_id%',	// корневая страница - текущая активная
			'min_level'	=> 2,	// минимальный уровень страниц 
			'max_level'	=> 3,	// максимальный уровень страниц 
			
			'prefix'	=> '<ul>',
			'suffix'	=> '</ul>',
			'link'		=> '<li><a class="%active% %parent%" href="%url%" >%title%</a> %submenu%',
			
			'divider'	=> " \n ",
			
			),
		));
	
	
	# путь к текущей странице ("хлебные крошки")
	
	<?if(!$Page->is_index){?>
	<style>
		#menu_path {
			font-size:75%;
			margin-bottom:6px;
			color:#333;	
		}
		#menu_path A, #menu_path B {color:#999;}
		#menu_path A:hover {color:orangered;}
	</style>
	<div id=menu_path >Вы сейчас здесь:
		<a href="/">Главная</a> > 
		<? 
		View::menu(array(
			'parent_id'		=> 0,	// от корня сайта
			
			'parent_active'	=> '<a href="%url%" >%title%</a> > %submenu%',
			'active'		=> '<a href="%url%" >%title%</a> ',
			
		))?>
	</div>
	<?}?>
	
	 
	
:TODO: что нужно доделать:  
	- макро-подстановки %active% %parent% %current%
	- parent_id с использвоанием макропеременных %current_id%, %parent_id%
	- %parent_id% , %parent_title% , %parent_url%
	- min_level, max_level (начальный и конечный уровень страниц меню (1,2,...) )
	- params_template / params_id - id набора преустановленных параметров (из каталога готовых меню)
	
***/

    static public
    function menu($params=array(), $pages_list=null)
    {
		// pr($params);
		
		$result = ''; 
		
		// определяем дефолтные шаблоны дизайна  // 
		$templates_default = 
		array(
			
			'prefix'	=> "\n<ul class=depth%depth% >",
			'suffix'	=> "\n</ul>",
			'link'		=> '
				<li class="%active% %current% %parent%" >
					<a class="%active% %current% %parent%" href="%url%" >%title%</a> 
					%submenu%
					',
			'divider'	=> "\n",
			
			// test: 
			'link' => '<li class="%active% %current% %parent%" ><a class="%active% %current% %parent%" href="%url%" >%title%</a> %submenu%',
			
		);
		
		// определяем дефолтные параметры выборки страниц 		
		$params_default = array( 
            'is_admin'  => 0,  
            'parent_id' => 0,
			'menu_id'   => null, 
            'max_depth'	=> 100,
			'min_level'	=> 1,
			'max_level'	=> null,
			'params_template' => '', // шаблон параметров из каталога шаблонов
			'depth'		=> 1, // текущая глубина меню при рекурсивном вызове 
            'return'	=> false, // возвращать (true) или выводить(false) результат функции
			);
        
		// устанавливаем все параметры меню  
		$params = array_merge($params_default, $params);  
        
		// pr($params);

		
		// если в параметрах не заданы шаблоны дизайна для меню - устанавливаем стандартные шаблоны
		if (!array_intersect(
				array_keys($params), 
				array('prefix', 'suffix', 'link', 'active', 'unactive', 'parent') 
			))
				$params = array_merge($params, $templates_default);
		
		
		
		// устанавливаем дополнительные шаблоны дизайна, с учетом их зависимостей
		
		$params['prefix']	= val($params['prefix']);
		$params['suffix']	= val($params['suffix']);
		$params['divider']	= val($params['divider']);
		
		$params['link']	= 
			find_is_set($params['link'], $params['unactive']);
		$params['active'] = 
			find_is_set($params['active'], $params['link']);
		$params['active_current'] = 
			find_is_set( $params['active_current'],  $params['active'] );
			
		$params['parent_active_current'] = 
			find_is_set(
						$params['parent_active_current'], 
						$params['parent_active'], 
						$params['parent'],
						$params['active_current']
						//,$params['active']
						
						);
			
		$params['parent_active'] = 
			find_is_set(
						$params['parent_active'], 
						$params['parent'], 
						$params['active']
						);
						
		$params['parent'] = 
			find_is_set(
						$params['parent'], 
						$params['link']
						);
			
		
		
		
		
		
		
		// pr($params);
		
		//test:
		// $result .= "($params[max_depth] - $params[depth] = " .($params['max_depth'] - $params['depth']) .")";
		
		// проверяем, нужно ли строить подменю ?
		if($params['max_depth'] - $params['depth'] < 1 )
			$params['sub_templates'] = false; // фиксируем 'флаг': подменю строить не нужно
		else 
		{	// иначе устанавливаем параметры и шаблоны для подменю
		
			if (empty($params['sub_templates']))  
			{
				$params['sub_templates']= (array)$params; // без (array) массив передается по ссылке и формирует рекурсию (php 5.1.6)
				// pr($params);
			}	
			else 
			{
				// pr($params);
				// устанавливаем все параметры для выборки страниц
				
				$params_options = array_get($params, array('is_admin', 'parent_id','menu_id', 'max_depth', 'depth', 'min_level', 'max_level' ));
				
				$params['sub_templates'] = array_merge(
											$params_options, 
											$params['sub_templates']
											);
				
				
				// pr($params_options);
				// pr($params['sub_templates']);
				
				// если не указаны шаблоны дизайна, то наследуем их все
				if (!array_intersect(
						array_keys($params['sub_templates']), 
						array('prefix', 'suffix', 'link', 'active', 'unactive', 'parent') 
					))
				{	
					$params_templates = array_get($params, array('prefix', 'suffix','link', 'active', 'active_current', 'parent' , 'parent_active', 'parent_active_current' ));
					
					$params['sub_templates'] = array_merge($params_templates, $params['sub_templates']);
				}
			}
			// pr($params);
			
			// рекурсивный вызов только возвращаем
			$params['sub_templates']['return']=true;
			
			// ищем и обрабатываем макропеременые наследования 
			foreach ($params['sub_templates'] AS $name=> &$tpl )
				if(!is_array($tpl) && strstr($tpl, '%inherit%'))
					$tpl = str_replace('%inherit%', $params[$name], $tpl);
			
			unset($tpl);	
			
			// pr($params);
			
		}
		// pr($params['sub_templates']);
		
		
		
		 // получаем массив страниц 
		$Pages = $pages_list ? $pages_list : Site::get_pages();
		
		
		// получаем свойства текущей страницы
		$current_page = (array)Core::$Page->data;
		$cur_id = val($current_page['id']);
		
		// собираем список id всех страниц-родителей текущей страницы (активных страниц в меню)
		$current_page['parents'] =  array(); 
		
		$pg = $current_page;
		while($parent_id = val($pg['parent_id']))
		{
			$current_page['parents'][] = $parent_id;
			$pg = (array)$Pages[$parent_id];
		}	
		
		
		// формируем массив макропеременных для автозамены
		// указываем текущую глубину 
		$replaces = array('%depth%' => $params['depth'] );
			// добавляем в массив автозамен все скалярные свойства текущей страницы:
			foreach ($current_page as $key=>$val)
				if (!is_array($val))
					$replaces["%currrent_{$key}%"] = $val;
			// TODO:: добавляем все свойства родительской страницы
			// ...  
			
			
 
        // прибавляем префикс
        // if(!empty($params['prefix']))
			$result .= str_replaces($params['prefix'], $replaces );
        // else pr($params);
		
		$counter=0; // счетчик пунктов меню (для корректной вставки разделителя)
		
		foreach($Pages as $page)
        {
         	
			$page = (array)$page;
            // pr($page);
			
			
			// фильтруем страницы по menu_id  
            if ($params['menu_id'] 
				&& !in_array($params['menu_id'], $page['show_in_menu'])) 
				
					continue;
				
            // pr($page);
			
			// фильтруем страницы по parent_id  
            if($params['parent_id'] != $page['parent_id'] )  continue;
			// pr($page);	

			// фильтруем страницы включенности - скрытые страницы показываем только в админ-режиме
			if (!$params['is_admin'] && !$page['show']) continue;
			// pr($page);
			
			// TODO::фильтруем страницы по min_level & max_level & current_page['level']

			// перед всеми пунктами кроме 1го, вставляем разделитель ( divider )
			if (++$counter > 1 )//&& !empty($params['divider'])) 
				$result .= $params['divider']; 
           		
			
			// вычисляем под-меню для обрабатываемой страницы (вычисляем заранее, чтобы узнать, является ли текущий пункт меню родителем)    
			// :TODO: Возможно, это улучшит скорость - если в начале функции нужно вычислять static array $pages_list_parent_id (id всех старниц-родителей) и вычислять $submenu ТОЛЬКО в том случае, если текущий page id присутствует в списке $pages_list_parent_id		
			
			if ($params['sub_templates'])
			{
				$params['sub_templates']['depth'] = $params['depth']+1;
				$params['sub_templates']['parent_id'] = $page['id'];
				
				$submenu = self::menu( $params['sub_templates'], $pages_list);
			}
			else 
				$submenu = ''; 
			
			// pr($submenu);
			// pr($params);
			
			
           
			// определяем статусы текущего пункта меню
			$is_current	= 	$page['id'] == $current_page['id'] ? 'current':'' ;
			$is_active	= 	in_array($page['id'],  array_merge($current_page['parents'], array($current_page['id'] ))) ? 'active':'';
			$is_parent 	= 	(bool)$submenu ? 'parent':'';
			$is_first	= 	$counter==1? 'first':'';
			
			
			
			// добавляем макропеременные для свойств текущего пункта меню
			$replaces["%current%"]	= $is_current;
			$replaces["%active%"] 	= $is_active;
			$replaces["%parent%"] 	= $is_parent;
			$replaces["%first%"] 	= $is_first;
			$replaces["%counter%"]	= $counter;
			
			 // определяем шаблон для отображения текущего пункта меню
			if	($is_parent && $is_current) $tpl = 'parent_active_current';
			else 
			if	($is_parent && $is_active) 	$tpl = 'parent_active';
			else 
			if	($is_parent) 	$tpl = 'parent';
			else 
			if	($is_current) 	$tpl = 'active_current';
			else 
			if	($is_active) 	$tpl = 'active';
			else
								$tpl = 'link';
			$item = $params[$tpl];
			
			$replaces["%tpl%"] = $tpl;
            
			// добавляем макропеременные, соответсвтующие свойствам страницы 
            foreach ($page as $key=>$val)
				if (!is_array($val) && $key!='depth')
					$replaces["%{$key}%"] = $val;
			
			// заменяем макропеременные в шаблоне текущего пункта меню
			$item = str_replaces($item, $replaces);
			
			
            // если подменю имеется, то вставляем вместо %submenu% 
            if ($submenu && strstr($item, '%submenu%'))
				$item = str_replace('%submenu%',$submenu, $item);    
            elseif ($submenu && (val($params['add_submenu'])||val($params['auto_submenu'])))
				$item .= $submenu;
			
			//если в шаблоне есть PHP код, то выполняем его
			if (strstr($item, '<?'))
			{
				// pr($item);
				$item = eval_phtml($item,  array('page'=> (object)$page, 'counter'=>$counter, 'params'=> &$params));
				// pr($item);
			}	
			// добавляем пункт меню (вместе с под-меню) к результирующему HTML коду
            $result .= $item;
			
        }
        
		// если пунктов меню нет - то результат пустой
		if (!$counter) $result='';
		else
		{
			// добавляем к результату суффикс (при необходимости парсим %level%)
			// if(!empty($params['suffix']))
				$result .= str_replaces($params['suffix'], $replaces);
			
			// обрабатываем завершение рекурсивного построения меню 
			if ($params['depth'] <=1 ) 
			{
				// очищаем код от необработанных макропеременных
				$result = preg_replace('/%[a-z_]+%/i', '' , $result);
				
				// pr($result);
			}
		}	
		
		if ($params['return']) return $result;
		else echo $result;
        
    }
	
	
	
	
	
	
	
	
	
	
	
	/***
	*	View::pagination($params=array() ) - генерирует постраничную навигацию
		
		@param: $params array
			Массив или объект с настройками и шаблонами для вывода навигации.
			При отсутствии массива или какого-то свойства в массиве $params, 
			используется свойство из $params_default (заданного в теле функции).
		
		@examle:
		Пример массива и описание возможных параметров:
		
			$params = array(
				// макс. количество ссылок в списке страниц
				links_count => 10, 	
				
				// шаблоны для вывода списка ссылок
				prefix 		=> '<div align=right> Страницы: ',
				suffix		=> '</div>',
				active	 	=> '<span >%pg%</span>',
				unactive 	=> '<a href=%url% >%pg%</a>',
				divider  	=> '&nbsp;&nbsp;',
				
				// префикс для первой страницы
				prefix_first 		=> '<div align=right> Страницы: ',
				// суффикс для последней стрвницы
				suffix_last		=> '</div>',
				
				
				// префикс, когда первая страница не отображается
				prefix_middle 		=> '',
				// суффикс, когда последняя страница не отображается
				suffix_middle		=> '',
				
				// true = возвращать результат, false (default) = печатать результат
				'return'	=> false,
				
			);
		
		В шаблонах можно применять следующие макропеременные: 
				
			%pg% - номер текущей страницы
			%pg_prev% - предыдущая страница
			%pg_next% - следующая страница
			%pg_first% - первая страница (1)
			%pg_last% - последняя страница 
			
			%url% - URL для текущей страницы
			%url_prev% - URL для предыдущей страницы
			%url_next% - URL для следующей страницы
			%url_first% - URL для первой страницы
			%url_last% - URL для последней страницы 				
			
			%total% - общее число элементов (записей)
			%start% - номер начального элемента на странице
			%end%	- номер последнего элемента на странице
			%per_page% - количество элементов на странице	
			
	*/
	static public
	function pagination($params=array())
	{
		// получаем параметры построения постраничной навигации для текущей страницы сайта
		$pagination =& Core::$Page->pagination;
		
		// описываем настройки по умолчанию (будут задействованы, если таковые не указаны в массиве с параметрами функции)
		$params_default = array(
			
			'pg'			=> $pagination->pg,//текущая страница
			'total' 		=> $pagination->total,//общее число элементов(записей)
			'per_page'	=> $pagination->per_page,//число элементов на странице
			
			'links_count' => 10, // макс. количество ссылок в списке номеров страниц
			
			// true = возвращать результат, false = печатать результат
			'return'	=> false,
		);
		// вычисляем действующие настройки
		$params = array_merge($params_default, (array)$params);
		
		
		// определяем начальный и конечный номер в списке страниц 
		$radius  = ceil($params['links_count']/2);
		$max_pg  = ceil($params['total']/ $params['per_page']);
		$i_start = max(1, $params['pg'] - $radius);
		$i_end 	 = min($params['pg'] + $radius, $max_pg);
		// определяем состояние навигации 
		$is_first = $params['pg']==1;
		$is_last = $params['pg']>=$max_pg;
		$is_medium_prefix = $i_start > 1;
		$is_medium_suffix = $i_end < $max_pg; 
		
		
		// вычисялем шаблоны для построения навигации
		$templ = array(
			
			'prefix' 	=> '<div align=right> Страницы: ',
			'suffix'	=> '</div>',
			'active'	=> '<span >%pg%</span>',
			'unactive' 	=> '<a href=%url% >%pg%</a>',
			'divider'  	=> '&nbsp;&nbsp;',
		);

		if ( isset($params['prefix']) OR isset($params['suffix']) OR isset($params['active']) OR isset($params['unactive']) OR isset($params['divider']) 
		)
		$templ = array(
			'divider'	=> val($params['divider']),
			
			'unactive'	=> val($params['unactive']),
			'active'	=> val($params['active'], val($params['unactive'])),
			
			'medium_prefix'	=> val($params['medium_prefix']),
			'medium_suffix'	=> val($params['medium_suffix']),
			
			'prefix'	=> val($params['prefix']),
			'suffix'	=> val($params['suffix']),
			
			'prefix_first'	=> val($params['prefix_first'], $params['prefix']),
								
			'suffix_first'	=> val($params['suffix_first'],val($params['suffix'])),
			
			'prefix_last'	=> val($params['prefix_last'], val($params['prefix'])),
			'suffix_last'	=> val($params['suffix_last'], val($params['suffix'])),
			
			'one_page'	=> val($params['one_page']),
			
		);
		//pr($templ);
		//pr($params);
		
		$templ['prefix_first'] = val($templ['prefix_first'], $templ['prefix']);
		$templ['prefix_last'] = val($templ['prefix_last'], $templ['prefix']);
		
		$templ['suffix_first'] = val($templ['suffix_first'], $templ['suffix']);
		$templ['suffix_last'] = val($templ['suffix_first'], $templ['suffix']);
		
		$templ['active'] = val($templ['active'], $templ['unactive']);
		$templ['one_page'] = val($templ['one_page']);
		
		
		
		
		//pr(self::get_pg_url(1,  $params));
		
		// вычисляем значения подстановочных макропеременных
		$replaces=array(
			'%pg_active%'	=> $params['pg'],
			'%pg_prev%'	=> $params['pg']-1,
			'%pg_next%'	=> $params['pg']+1, 
			'%pg_first%'	=> 1, 
			'%pg_last%' 	=> $max_pg,
			
			'%url_active%'	=> self::get_pg_url($params['pg'],  $params),
			'%url_prev%'	=> $params['pg']<=1? '' : self::get_pg_url($params['pg']-1, $params),
			'%url_next%'	=> $params['pg']>=$max_pg? '' : self::get_pg_url($params['pg']+1, $params),
			'%url_first%'	=> self::get_pg_url(1, $params),
			'%url_last%'	=> self::get_pg_url($max_pg, $params),
			
			'%total%'			=> $params['total'],
			'%start_active%'	=> '',
			'%end_active%'	=> '',
			'%per_page%'		=> $params['per_page'],
			
			
		);
		
		
		// Обрабатываем случай "Только одна страница"
		if ($max_pg<=1) return val($templ['one_page']); // TODO: когда понадобиться, нужно проработать обработку шаблона для отсутствия списка страниц
		
		// строим шаблон для списка из нескольких страниц
        $result = ''; 
		
		
        // прибавляем префикс, 
		$templ['prefix'] = 	$is_first? $templ['prefix_first'] : 
								($is_last? $templ['prefix_last'] : 
									$templ['prefix']);
		$result .=  str_replaces($templ['prefix'], $replaces);
		//pr($is_first);
		//pr($templ['prefix_first']);
		
		
		if ($is_medium_prefix) 
			$result .=  str_replaces($templ['medium_prefix'], $replaces);
		
        // перебираем все страницы в диапазоне
        for ($i= $i_start; $i<= $i_end; $i++ )
		{
		  
			
			// выбираем нужный шаблон 
			$tpl = ($i==$params['pg']) ? $templ['active'] : $templ['unactive'];
			
			//pr($i);
			$url = self::get_pg_url($i,  $params);
			
			
			$tpl = str_replace('%url%', $url, $tpl);
			$tpl = str_replace('%pg%' , $i, $tpl);
			
			$result .= $tpl;
			
			// добавляем разделитель
			if ($i < $i_end)
				$result .= $templ['divider'];
			
			//pr($i);	
		
		}	
		// pr($replaces);
		
		if ($is_medium_suffix) 
			$result .=  str_replaces($templ['medium_suffix'], $replaces);
		
		$templ['suffix'] = 	$is_first? $templ['suffix_first'] : 
								($is_last? $templ['suffix_last'] : 
									$templ['suffix']);
		$result .=  str_replaces($templ['suffix'], $replaces);
			
        //pr($result);
		
		if ($params['return']) return $result;
		else echo $result;
        
	}
	
	// вычисляем URL для страницы с заданным номером
	// добавляя/заменяя в текущем url переменную pg
	static 
	function get_pg_url($pg)
	{
		$url  = $_SERVER['REQUEST_URI'];
		$url  = preg_replace('/[&?]pg=[^&]*/','',$url);
		if ($pg<=1) return $url;
		
		$url .= strstr($url ,'?') ? '&' : '?';
		$url  = str_replace('?&', '?', $url) .'pg='.$pg;
		return $url;
	}
	
	// список директорий для поиска шаблонов
	static $templ_dirs=array();
	
	// регистрирует директорию для поиска шаблонов
	static
	function register_dir($dir)
	{
		if (is_dir($dir)) self::$templ_dirs[] = $dir;
	}
	
	
	// вычисляет уникальный идентификатор виджета
	// $container_id - это идентификатор страницы или другого элемента, внутри которого вставлен виджет (глобальный блок - block_2, статья - post_43 и т.п.)
	static
	function widget_uid($widget_id, $container_id)
	{	
		static $counter=1;
		return 	$widget_id.'_'.(is_numeric($container_id)?'pg_'.$container_id : find_not_empty($container_id, $counter));
	}
	
	// возращает HTML-код виджета 
	static
	function get_widget($widget_id, $params='')
	{	
		return self::widget($widget_id, $params, true);
	}
	
	
	// отображает или возращает HTML-код виджета 
	static
	function widget($widget_id, $widget_params='', $return=false)
	{
		// pr_($widget_id, $widget_params);
		
		// преобразуем строку с параметрами в массив
		if (is_string($widget_params)) parse_str($widget_params, $widget_params);
		
		$widget_class 	 = Core::$Widgets[$widget_id]->module;
		// pr(Core::$Widgets);
		
		// вычисляем уникальный идентификатор виджета
		$widget_params['widget_uid']= self::widget_uid($widget_id, val($widget_params['page_id']));
		
		
		// pr_($widget_id, $widget_class, $widget_params);
		
		$widget_params['widget_template']=
		$widget_template = View::get_template("$widget_class/$widget_id", $widget_params);
				
		$widget_content  = '';
				
		// pr("\$widget_template=$widget_template");
		
		// если существует метод для отобюражения виджета - вызываем его
		if (method_exists($widget_class, $func ='widget_' . $widget_id))
		{
			$widget_content =  call_user_func(
									array($widget_class, $func), 
									$widget_params
									);
		}	
		// иначе - просто используем файл с шаблоном виджета
		else if ($widget_template && file_exists($widget_template))
		{
			//pr($widget_params);
			$widget_content = eval_template($widget_template, //null, 
				array_merge(
					$widget_params, 
					array('params'=>$widget_params)
				)
			);
		}
		
		if ($return) return $widget_content;
		else echo $widget_content;
	}
	
	
/** get_template($template_type, $params) 
	Возвращает путь к шаблону, по его идентификатору в параметрах виджета $params или находя его в папке дизайна или папке модуля по соответствию его типу $template_type
	
	(Если шаблон указан в URL и разрешено парсить URL, возвращает его)
	Если шаблон указан в $params и файл существует, возвращает его.
	Иначе, ищет: (1)шаблон такого же типа в папке модуля, затем (2)стандартный шаблон в папке дизайна и затем (3)стандартный шаблон в папке модуля.
		
**/
	static
	function get_template($template_type, $params=array())
	{
		// pr($template_type, $params);
		// pr(find_file_exists(val($params['template']), true));
		// pr_($params['template']);
		// if($file = find_file_exists(GET('template').'.php')) return $file;
		
		// преобразуем строку с параметрами в массив
		if (!is_array($params)) parse_str($params, $params);
		
		list($module_id, $templ_type_needle) = explode('/',$template_type);
		$templ_name_needle = $templ_type_needle.'.php';
		
		$module_tpl_dir = MODULES_DIR."/$module_id/templates";
		// $design_tpl_dir = Config('site')->theme_dir;
		$design_tpl_dir = Config('site')->design_dir;
		
		$check_templates = array();
		
		// если шаблон виджета задан в параметрах, то интерпретируем его и добавляем соответствующие пути в очередь поиска шаблона
		if($templ_id = val($params['template']))
		{
			if(!strstr($templ_id,':')) $templ_id="design:".$templ_id;
			
			list($templ_dir, $templ_name) = array_trim(explode(':', $templ_id));
			list ($templ_type_params, $templ_subtype) = explode(' ', $templ_name.' ');
			
			
			$templ_name .= '.php';
			if ($templ_type_params != $templ_type_needle)
				$templ_name = 	$templ_type_needle
								.($templ_subtype? ' '.$templ_subtype :'')
								.'.php';
			
			// pr($templ_name);
			
			// ищем точное совпадение в папке шаблонов сайта
			if ($templ_dir=='design')
			$check_templates[] = "$design_tpl_dir/$templ_name";
			
			// ищем точное совпадение в папке шаблонов модуля
			$check_templates[] = "$module_tpl_dir/$templ_name";
			
		}
		
		// ищем стандартный шаблон в папке шаблонов сайта
		$check_templates[] = "$design_tpl_dir/$templ_name_needle";
		
		// ищем стандартный шаблон в папке шаблонов модуля
		$check_templates[] = "$module_tpl_dir/$templ_name_needle";
		
		// pr($check_templates);
		
		// определяем первый существующий файл из списка поиска
		$file = find_file_exists($check_templates);
		
		// pr_($file);	exit;
		
		return $file;				
	}
	
	
/** get_templates($template_type) 
	возвращает список (ассоциативный массив) всех доступных шаблонов указанного типа
	
	Обычно такой список используется для построения выпадающего меню для выбора шаблона, так что формат элемента списка следующий: 
	'dir_type: template_filename_wo_ext'=>'tempalte_title'
	
	Например:  
		'module: posts'=>'Статьи (шаблон модуля)'
		'design: posts gallery'=>'Фотогалерея (шаблон сайта)'
	
	@params $template_type -  тип шаблона, строка вида 'module_id/template_id' (например: 'blog/posts' ) 
	
	
***/
	static
	function get_templates($template_type)
	{
		list($module_id, $template_id) = explode('/',$template_type);
		
		$module_tpl_dir = MODULES_DIR."/$module_id/templates";
		// $design_tpl_dir = Config('Site')->theme_dir;
		$design_tpl_dir = Config('Site')->design_dir;
		
		$module_tpl_url = MODULES_URL."/$module_id/templates";
		// $design_tpl_url = Config('site')->theme_url;
		$design_tpl_url = Config('site')->design_url;
		
		
		//pr($);
		
		$templates=array();
		
		
		// считываем шаблоны модуля
		$tpls = glob("$module_tpl_dir/$template_id{, *}.php", GLOB_BRACE);
		// pr($tpls);
		
		if ($tpls)
		{
			foreach ($tpls as $tpl)
			{
				$tpl_id = "module: ".file_wo_ext(basename($tpl));
				$tpl_title = html("<module dir>/".basename($tpl));
				
				$templates[$tpl_id] =  $tpl_title; 
				
			}		
		}
		
		// считываем шаблоны из папки дизайна
		$tpls = glob("$design_tpl_dir/$template_id{, *}.php", GLOB_BRACE);
		// pr($tpls);
		
		if ($tpls)
		{
			foreach ($tpls as $tpl)
			{
				$tpl_id = "design: ".file_wo_ext(basename($tpl));
				$tpl_title = html("<design dir>/".basename($tpl));
				
				$templates[$tpl_id] =  $tpl_title; 
			}		
		}
		
		
		return $templates;
		
	}
	
	
	
	/**
	 * View::template($template, $data, $vars=array()) - исполняет файл PHP шаблона $template и вставляет в него содержимое массива $data . Отображает (или возвращает) HTML код.
	 *
	 * @param string $template - путь к файлу шаблона
	 
	 * @param string/array $data  - данные для вставки в шаблон. 
	 *      Если $data - строка, то данные вставляются в переменную $content. 
	 *      Если $data - одномерный ассоциативный массив, то данные вставляются в  переменые, соответветствующие ключам массива.  
	 *      Если $data - двумерный массив, то в шаблон передается переменная $data без изменений, и шаблон должен будет обработать $data в цикле.
	 
	 * @param array $vars - ассоциативный массив с ссылками на переменные, которые должны быть доступны в шаблонах
	 
	 * @param array $options - опции обработки шаблона
			$options['return'] =1	 - возвращать HTML код (по умолчанию выводиться)
			$options['eval_empty']=1 - обрабатывать шаблон	при отсутствии данных
	 
	 */
	static
	function template($template, $data, $vars=array(), $options=array())
	{
		//echo "$template | ";
		// pr($template);
		
		
		// Ищем файл PHP-шаблона в зарегистрированных директориях
		if (!file_ext($template)) $template.='.php';
		if ($template && !file_exists($template) && self::$templ_dirs)
			foreach (self::$templ_dirs AS $dir)
				if (file_exists($t="$dir/$template"))
					{$template = $t; break;}
		if (!file_exists($template)) $template='';
		
		// pr(self::$templ_dirs);
		// pr($template);	
		// pr($data);
		
		// если данных нет - то и результат шаблонизации пустой. 
		if (!$data) return ''; //(TODO: возможно в будущем понадобиться обрабатывать пустые данные в шаблоне, нужно предусмотреть опцию)
		
		// если $data - строка, назначаем строку в переменную $content   
		if (is_string($data) && $data) $data = array('content'=>$data);
		
		// если $data - одномерный массив - извлекаем его свойства 
		if (is_object($data) || (is_array($data) && !isset($data[0])))
			extract( (array)$data);
		
		// переменные из $vars перекрывают одноименные переменные из $data
		if ($vars && is_array($vars)) 
			extract($vars); 	

		// если шаблон не существует - кладем в результат свойство $content 
		if (!$template || !file_exists($template))    
		{
			$result = val($content);
		}
		else
		{
			$error_level_old = error_reporting(E_ALL&~ E_NOTICE);// для удобства позволяем использовать в шаблоне неинициализированные переменные и индексы без вывода ошибок
			
			//echo "$template | ";
			
			// считываем результат исполнения шаблона через буфер
			ob_start();
			include ($template);
			$result = ob_get_contents();
			ob_end_clean();
			//echo "$template | ";
			
			error_reporting($error_level_old);// устанавливаем прежний уровень ошибок
		}
		//pr($result);
		
		if (empty($options['return'])) echo $result;
		else return $result;
	}
	
	
	
/** View::field($params) - выводит поле формы

	! значения, подставляемые в параметры тегов (onchange, onclick, style, ...) нужно заключать в одинарные кавычки
	
	Примеры:
	
	// Текстовое поле (обычно длинное)
	View::field(array(
		'type'	=> 'text',
		'label'	=> 'Название',
		'name'	=> 'data[title]',
		'value'	=> $data->title,
	));
	
	// короткое текстовое поле 
	View::field(array(
		'type'	=> 'text small',
		'label'	=> 'Автор',
		'name'	=> 'data[autor]',
		'value'	=> $data->autor,
	));
	
	// текстовое многострочное поле
	View::field(array(
		'label'	=> 'Описание сайта',
		'desc'	=> 'Описание сайта используется в теге DESCRIPTION',
		'type'	=> 'textarea',
		'name'	=> 'data[site_description]',
		'value'	=> $data->site_description,
	));
	
	// текстовое многострочное поле с сохранением переносов
	View::field(array(
		'type' 	=> 'textarea nl2br',
		'label'	=> 'Заголовок сайта',
		'name'	=> "data[{$block->id}]",
		'value'	=> $block->content,
	)); 
	
	
	// визуальный редактор
	View::field(array(
		'label'	=> 'Содержимое',
		'type'	=> 'wysiwyg',
		'name'	=> 'data[content]',
		'value'	=> $data->content,
	));
	
	// загрузка файла-картинки
	View::field(array(   
			'type'	=> 'file',
			'label'	=> 'Картинка',
			'name'	=> 'data[img]',
			'value'	=> $data->img,
	));
	
	// выпадающий список
	View::field(array(
		'type'	=> 'select',
		'label'	=> 'Опубликовано на странице',
		'name'	=> 'data[page_id]',
		'value'	=> $select_id,
		'options_title'	=> '--- выберите страницу ---',
		'options'		=> $options,
		'onchange'		=> 'show_warning(); $("data[title]").focus();' ,
	));
	
		$options - это либо ассоциативный массив вида:
			$options['value']='title' ,  
		
		либо двумерный массив вида: 
			$options[]= array(
					'value'	 => -1,
					'title'	 =>  '(не опубликовано)',
					'params' => ' class=grey ',
			);

	// Дата 
	View::field(array(
				'type'	=> 'date',
				'label'	=> 'Дата',
				'desc'	=> 'в формате ДД-ММ-ГГГГ или ДД-ММ-ГГГГ ЧЧ:ММ',
				'name'	=> 'data[datetime]',
				'value'	=> $data->datetime,
			));		
			
	// checkbox - галочка 
	View::field(array(
		'type'	=> 'checkbox',
		'label'	=> 'Отображать статью',
		'name'	=> 'data[show]',
		'value'	=> $data->show,
		));		
			
			
**/	
	
	
	
	static
	function field($data)
	{
		// pr($data);
		return self::template('fields', $data);
	}
	
	/**
	 * attach_wysiwyg($params) - подключает к странице визвинг-редактора, указанный в настройках CMS. Редактор подключается ко всем TEXTAREA или другим блокам, где указан class=wysiwyg
	 */
	// Внимание: если визвинг NicEdit полключается перед TEXTAREA, то обязательно нужно закрыть тег P перед ней (при незакрытом P NicEdit почему то не работает в IE6)
	static
	function  attach_wysiwyg($params=null)
	{
		static $wys_done=false;
		
		//pr(Admin::$Wysiwygs);
		$wysiwyg_id 	= Admin::$Config->wysiwyg;
		$wysiwygs 		= Admin::get_wysiwygs();
		$wysiwyg_file 	= val($wysiwygs[$wysiwyg_id]->file);
		
		if ($wysiwyg_id && $wysiwyg_file && file_exists($wysiwyg_file) && !$wys_done)
		{
			// подключаем файлы визвинг редактор только один раз
			$wys_done=true;
			
			// подключаем общие методы Wysiwyg
			echo 	'<script src="'
					.Admin::$Config->templ_url.'/files/wysiwyg.js'   
					.'" ></script>'
					;
			
			// подклчюаем методы и инициализацию конкретного визвинг-редактора
			include_once($wysiwyg_file);
		}
	
	}

}

/*
<?=InfoBlocks::view('site_title')?>
		
		<?//=View::infoblock('site_title')?>
		
		<?
		
		Core::register_view($view_id, $func_name)
		Core::register_view( array($view_id=>$func_name, ));
		
		foreach (Core::$Views as $view_id=>$func_name)
		$code. = "
			function $view_id()
			{
				return call_user_func_array('$func_name', func_get_args());
			}
		";
		
		$code = "class View extends View_System{
		$code
		}
		"
		
		
		?>
*/



/***** 
Динамически формируем класс View 
из функций, зарегистрированных модулями 
*****/

// список зарегистрированных генераторов HTML-кода
// формат списка: array('view_id'=>'ModuleClassname::funcname', ... )
$view_methods = Core::$view_methods;
//pr($view_methods);

// шаблон для функции-алиаса
$func_tpl='
	static public 
	function %view_id%()
	{
		$args = func_get_args();
		return call_user_func_array(
			array("%view_module%","%view_func%"), 
			$args
			);
	}
';

// формируем код для конечного класса 
$code = "class View extends View_Core { \n";

if($view_methods)
foreach ($view_methods AS $view_id=>$view_method)
{
	list($view_module, $view_func) = explode('::',$view_method);
	
	// в цикле добавляем методы модулей к классу View
	$code .= str_replaces($func_tpl, 
				array(
					'%view_id%'		=> $view_id,
					'%view_module%'	=> $view_module,
					'%view_func%'	=> $view_func,
				));
}
$code .= '}';
//pr($code);


// выполняем код класса View
eval($code);

/*
Cистема наименований шаблонов
(заметки)

Что нужно именовать отдельно -шаблоны для чего:
Для страниц  - обычная, главная, версия для печати, для мобильников и прочее. Один и тот же контент может быть обрамлен различными шаблонами старницы
Для контента страниц - контент может енерировать различными модулями - Site, Blog, Users, /_user/slava-vvs/foto
Для виджетов / или видов  - view posts , view blog , view post - представление опредленной информации
Для настроек  - settings / form / 
Для меню / навигации
Шаблон старницы - page.php / page *.php *= action страницы 
Шаблон контента для главной страницы  - page_content index / content page index
Шаблон контента для обычной страницы  - page_content / content page
Шаблон для списка статей - view posts *.php 
Шаблон для формы связи view mailform *.php
Шаблоны для постаничной навигации: view pagination *.php
Шаблоны для полей форм view fields.php
<Категория шаблона> <идентификатор обработчика> 

Шаблон для счетчика
Шаблоны для формы связи - их моджет быть много - mailform 1, mailform blue, mailform 3, --- и их модно выбрать в настройках виджета - поиск ведется сначала в папке дизайна, затем, в папке шблонов соответствующего модуля. Так что шаблон можно иметь либо идентификатор метода (mailform) либо идентификатор мдля+метод (mailform_replays) или один  только идентификатор модуля (blog, mailform, counter)  - что предполагает выбор метода по умолчанию (posts , form , counter)
page, page_content - эти идентификаторы категории шаблона регистрируется модулем Site
post , posts  - эти идентификаторы категории шаблона регистрируется модулем Blog
mailform  -  эта категория шаблона регистрируется модулем Mailform

В настройках страницы можно выбрать шаблон для страницы - выбираются из папки дизайна и папки модуля Site (стандартные шаблоны print, 404, empty)
В настройках виджета можно выбрать шаблон для виджета -- выбираются из папки дизайна и папки соовтетсвтующего модуля (templates) -шаблоны для виджетов: счетчик, почтовая форма, лента статей, одна статья, 
 Как быть с шаблонами для постраничной навигации? Навигации пути? Шаблоны для меню? Как и откуда они выбираются? 
Вероятно из модуля site /папки дизайна
А где это натсраивается? Например постраничная навиация для ленты статей (в виджете ленты статей) / всего сайта (в настройках темы дизайна)
pagination - регистрируется модулем Blog
menu - регистрируется модулем Site 

page - соответствует метод view::page = Site::view_page
page_content - соответствует методу  Site::view_contetn = View::page_content 
page_content index -  соответствует методу  View::page_content для действия action_index
page 404 - шаблон страницы для действия Site::action_404

*/